import 'dart:async';
import 'dart:isolate';

import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';

void main() async {
  runApp(MaterialApp(
    home: Scaffold(
      appBar: AppBar(
        title: const Text('isolate'),
      ),
      body: Container(
        child: Center(
          child: const Text('hello world'),
        ),
      ),
    ),
  ));

  print('fibonacci result using isolate:${await asyncFibonacci(50)}');

  /// 50 大概会话费180秒左右，同时通过compute方法执行的效率会比通过直接创建Isolate高一些
  var fibonacciResult = await compute<int, int>(_1.fibonacciResult, 50);
  print('fibonacci result using compute:$fibonacciResult');
}

class _1 {
  static int fibonacciResult(int input) {
    var startInMillis = DateTime.now().millisecondsSinceEpoch;
    var fibonacci = syncFibonacci(input);
    var endInMillis = DateTime.now().millisecondsSinceEpoch;
    print(
        'fibonacci result using compute take:${(endInMillis - startInMillis) / 1000}s');
    return fibonacci;
  }
}

Future<dynamic> asyncFibonacci(int n) async {
  final response = new ReceivePort();

  var broadcastStream = response.asBroadcastStream();
  broadcastStream.listen((data) {
    print('data:$data');
  }, onError: (e) {
    print('error:$e');
  });
  var data = _Data();
  data.port = response.sendPort;
  data.param = "jdflafaksfjs";
  var isolate = await Isolate.spawn(_isolate, data);
  if (isolate != null) {
    /// 向新线程发送数据的SendPort对象，通过该对象向新线程发送数据
    final sendPort = await broadcastStream.first as SendPort;
    final answer = new ReceivePort();
    sendPort.send([n, answer.sendPort]);
    var result = await answer.first;
    response.close();
    answer.close();
    return result;
  } else {
    print('create isolate fail.........');
    return null;
  }
}

class _Data {
  SendPort port;
  String param;
}

void _isolate(_Data param) async {
  final port = new ReceivePort();
  var initialReplyTo = param.port;
  if (initialReplyTo == null) {
    port.close();
    Isolate.current?.kill(priority: Isolate.immediate);
    return;
  }
  initialReplyTo.send(port.sendPort);
  print('background isolate receive data:${param.param}');
  var first = await port.first as List<dynamic>;
  final data = first[0] as int;
  final send = first[1] as SendPort;
  var startInMillis = DateTime.now().millisecondsSinceEpoch;
  var fibonacci = syncFibonacci(data);
  var endInMillis = DateTime.now().millisecondsSinceEpoch;
  print(
      'fibonacci result using isolate take:${(endInMillis - startInMillis) / 1000}s');
  send.send(fibonacci);
  port.close();
  Isolate.current?.kill(priority: Isolate.immediate);
}

int syncFibonacci(int n) {
  return n < 2 ? n : syncFibonacci(n - 2) + syncFibonacci(n - 1);
}
